#pragma once

#include "TcpServer.hpp"
#include "Socket.hpp"
#include "comm.hpp"
#include "Util.hpp"

using namespace SocketModule;

const std::string gspace = " ";
const std::string glinespace = "\r\n";
const std::string gssep = ": ";

const std::string webroot = "./wwwroot";
const std::string homepage = "/index.html";
const std::string page_404 = "/404.html";

class HttpRequest
{
public:
    HttpRequest() : _blankline(glinespace), _is_interact(false) {}

    std::string Serialize()
    {
        return " ";
    }

    void ParseReqLine(std::string &reqline)
    {
        std::stringstream ss(reqline);
        ss >> _method >> _uri >> _version;
    }

    // 认为拿到了一个完整的请求
    bool Deserialize(std::string &reqstr)
    {
        bool res;
        // 1.提取请求行
        std::string reqline;
        res = Util::ReadOneLine(reqstr, &reqline, glinespace);
        LOG(LogLevel::DEBUG) << "reqline: " << reqline;
        // 对请求行反序列化
        ParseReqLine(reqline);
        LOG(LogLevel::DEBUG) << "Method: " << _method;
        LOG(LogLevel::DEBUG) << "Uri: " << _uri;
        LOG(LogLevel::DEBUG) << "Version: " << _version;
        if (_uri == "/")
            _uri = webroot + homepage;
        else
        {
            _uri = webroot + _uri;
        }
        std::string temp = "?";
        auto pos = _uri.find(temp);
        if (pos == std::string::npos)
            return true;

        _args = _uri.substr(pos + temp.size() );
        _uri = _uri.substr(0, pos);
        _is_interact = true;
        return true;
    }

    bool IsInteract() { return _is_interact; }
    std::string Uri() { return _uri; }
    std::string Args() { return _args; }

    ~HttpRequest() {}

private:
    std::string _method;
    std::string _uri;
    std::string _version;

    std::unordered_map<std::string, std::string> _headers;
    std::string _blankline;
    std::string _text;

    bool _is_interact;
    std::string _args;
};

class HttpResponse
{
public:
    HttpResponse() : _blankline(glinespace), _version("HTTP/1.1") {}

    // 成熟的http 应答序列化不需要依赖任何第三方库
    std::string Serialize()
    {
        std::string status_line = _version + gspace + std::to_string(_code) + gspace + _desc + glinespace;
        std::string resp_header;
        for (auto &header : _headers)
        {
            std::string line = header.first + gssep + header.second + glinespace;
            resp_header += line;
        }

        return status_line + resp_header + _blankline + _text;
    }

    bool Deserialize(std::string &respstr)
    {
        return true;
    }

    void SetTargeFile(std::string file)
    {
        _targetfile = file;
    }

    void SetCode(int code)
    {
        _code = code;
        switch (_code)
        {
        case 200:
            _desc = "OK";
            break;
        case 404:
            _desc = "Not Found";
            break;
        case 301:
            _desc = "Moved Permanently";
            break;
        case 302:
            _desc = "See Other";
            break;
        default:
            break;
        }
    }

    void SetText(const std::string &t)
    {
        _text = t;
    }

    void SetHeader(const std::string &key, const std::string &value)
    {
        auto iter = _headers.find(key);
        if (iter != _headers.end())
            return;
        _headers.insert(std::make_pair(key, value));
    }

    std::string Uri25Suffix(std::string &filename)
    {
        auto pos = filename.rfind(".");
        if (pos == std::string::npos)
        {
            return "text/html";
        }
        std::string suffix = filename.substr(pos);
        if (suffix == ".html" || suffix == ".htm")
            return "text/html";
        else if (suffix == ".jpg")
            return "image/jpeg";
        else if (suffix == "png")
            return "image/png";
        else
            return "";
    }

    bool MakeResponse()
    {
        if (_targetfile == "./wwwroot/redir")
        {
            SetCode(301);
            SetHeader("Location", "https://www.qq.com/");
            return true;
        }
        bool res = Util::ReadFile(_targetfile, &_text);
        int filesize = 0;
        if (!res)
        {
            LOG(LogLevel::DEBUG) << "client request: " << _targetfile << " but not found";
            SetCode(404);
            _targetfile = webroot + page_404;
            filesize = Util::FileSize(_targetfile);
            Util::ReadFile(_targetfile, &_text);
            std::string suffix = Uri25Suffix(_targetfile); // 后缀格式
            SetHeader("Conent-Type", suffix);
            SetHeader("Set-Cookie", "username:jiuqi");
            // SetHeader("Content-Length", std::to_string(filesize));
            // SetCode(302);
            // SetHeader("Location", "http://124.221.37.37:8080/404.html");
        }
        else
        {
            SetCode(200);
            filesize = Util::FileSize(_targetfile);
            std::string suffix = Uri25Suffix(_targetfile); // 后缀格式
            SetHeader("Conent-Type", suffix);
            // SetHeader("Content-Length", std::to_string(filesize));
        }
        // filesize = _text.size();
        // std::cout << _text << std::endl;
        // std::cout << _text.size() << std::endl;
        // std::cout << filesize << std::endl;

        SetHeader("Content-Length", std::to_string(filesize));
        return true;
    }

    ~HttpResponse() {}

    std::string _version;
    int _code;
    std::string _desc;

    std::unordered_map<std::string, std::string> _headers;
    std::string _blankline;
    std::string _text;

    // 其他属性
    std::string _targetfile;
};

using http_func_t = std::function<void(HttpRequest &req, HttpResponse &resp)>;

class Http
{
public:
    Http(uint16_t port) : _TcpServer(std::make_unique<TcpServer>(port))
    {
    }

    void HandlerHttpRquest(std::shared_ptr<Socket> &socket, InetAddr &client)
    {
        std::string httpreqptr;
        int n = socket->Recv(&httpreqptr);
        if (n > 0)
        {
            HttpRequest req;
            HttpResponse resp;
            req.Deserialize(httpreqptr);
            if (req.IsInteract())
            {
                if(_route.find(req.Uri()) == _route.end())
                {
                    
                }
                else
                {
                    _route[req.Uri()](req, resp);
                    std::string response_str = resp.Serialize();
                    socket->Send(response_str);
                }
            }
            else
            {
                resp.SetTargeFile(req.Uri());
                resp.MakeResponse();

                // std::string filename = req.Uri();
                // HttpResponse resp;
                // resp._version = "HTTP/1.1";
                // resp._code = 200;
                // resp._desc = "OK";
                // Util::ReadFile(filename, &resp._text);

                std::string response_str = resp.Serialize();
                socket->Send(response_str);
            }
        }

// #define DEBUG
#ifdef DEBUG
        std::string httpreqptr;
        socket->Recv(&httpreqptr);
        std::cout << httpreqptr;

        // 直接构建应答, 内存级别+固定
        HttpResponse resp;
        resp._version = "HTTP/1.1";
        resp._code = 200;
        resp._desc = "OK";

        std::string file = webroot + homepage;
        Util::ReadFile(file, &resp._text);
        std::string response_str = resp.Serialize();
        socket->Send(response_str);
#endif
    }

    void Start()
    {
        _TcpServer->Start([this](std::shared_ptr<Socket> &socket, InetAddr &client)
                          { this->HandlerHttpRquest(socket, client); });
    }

    void RegisterServer(const std::string name, http_func_t h)
    {
        std::string key = webroot + name;
        auto iter = _route.find(key);
        if (iter == _route.end())
        {
            _route.insert({key, h});
        }
    }

    ~Http() {}

private:
    std::unique_ptr<TcpServer> _TcpServer;
    std::unordered_map<std::string, http_func_t> _route;
};